package be.nepherte.movmanager.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Key;

import be.nepherte.movmanager.client.MovManager;
import be.nepherte.movmanager.client.exceptions.NoSuchGenreException;

/**
 * This enum represents all possible genres available in MovManager. The list is
 * taken mostly from <a href="http://api.themoviedb.org/2.1/methods/Genres.getList">
 * http://api.themoviedb.org/2.1/methods/Genres.getList</a>.
 * 
 * <p>
 * This file is part of MovManager.
 * </p>
 * 
 * <p>
 * MovManager is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * </p>
 * 
 * <p>
 * MovManager is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * </p>
 * 
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * MovManager. If not, see <a
 * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses</a>.
 * </p>
 * 
 * @author	Bart Verhoeven
 * @version	0.1
 */
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Genre implements Serializable {
	private static final long serialVersionUID = 1L;
	/**Unique key identifier for this genre used for data storage.*/
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
	/**Name of the genre.*/
	@Persistent
	private String name;
	/**Movie this genre belongs to. A bidirectional mapping is used as required by JDO.*/
	@Persistent
	private Movie movie;
	
	/**
	 * Default empty constructor required by the Google RPC protocol.
	 */
	public Genre() {}
	
	/**
	 * Creates a new genre.
	 * 
	 * @param	name
	 * 			name of this genre
	 */
	private Genre(String name) {
		setName(name);
	}
	
	/**
	 * Retrieves the unique identifier for this genre.
	 * 
	 * @return	key
	 */
	public Key getKey() {
		return key;
	}

	/** Sets the unique identifier for this genre. Note that the key is
	 * automatically generated and assigned upon storage in the database. This
	 * method is only here to reconstruct this object upon retrieval from the
	 * database.
	 * 
	 * @param	key
	 *          the unique identifier belonging to this genre
	 */
	public void setKey(Key key) {
		this.key = key;
	}
	
	/**
	 * Gets the name of this genre.
	 * 
	 * @return	name
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * Sets the name for this genre.
	 * 
	 * @param	name
	 * 			the new name for this genre
	 */			
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Gets the movie this genre belongs too.
	 * 
	 * @return	movie
	 */
	public Movie getMovie() {
		return movie;
	}
	
	/**
	 * Sets the movie this genre belongs too.
	 * 
	 * @param	movie
	 * 			the movie this genre belongs too	
	 */
	public void setMovie(Movie movie) {
		this.movie = movie;
	}
	
	@Override
	public String toString() {
		return name;
	}
	
	/**
	 * Retrieves all currently available genres.
	 */
	public static final Genre[] values() {
		return new Genre[] { action(), adventure(), animation(), biography(), comedy(), crime(), documentary(), drama(), eastern(), erotic(), fantasy(), history(), horror(), mystery(), music(), musical(), romance(), sciencefiction(), sport(), thriller(), western() };
	}
	
	public static final Genre action() {
		return new Genre(MovManager.constants.genreAction());
	}
	
	public static final Genre adventure() {
		return new Genre(MovManager.constants.genreAdventure());
	}
	
	public static final Genre animation() {
		return new Genre(MovManager.constants.genreAnimation());
	}
	
	/**Biography genre.*/
	public static final Genre biography() {
		return new Genre(MovManager.constants.genreBiography());
	}
	
	/**Comedy genre.*/
	public static final Genre comedy() {
		return new Genre(MovManager.constants.genreComedy());
	}
	
	/**Crime genre.*/
	public static final Genre crime() {
		return new Genre(MovManager.constants.genreCrime());
	}
	
	/**Documentary genre.*/
	public static final Genre documentary() {
		return new Genre(MovManager.constants.genreDocumentary());
	}
	
	/**Drama genre.*/
	public static final Genre drama() {
		return new Genre(MovManager.constants.genreDrama());
	}
	
	/**Eastern genre.*/
	public static final Genre eastern() {
		return new Genre(MovManager.constants.genreEastern());
	}
	
	/**Erotic genre.*/
	public static final Genre erotic() {
		return new Genre(MovManager.constants.genreErotic());
	}
	/**Fantasy genre.*/
	public static final Genre fantasy() {
		return new Genre(MovManager.constants.genreFantasy());
	}
	
	/**History genre.*/
	public static final Genre history() {
		return new Genre(MovManager.constants.genreHistory());
	}
	
	/**Horror genre.*/
	public static final Genre horror() {
		return new Genre(MovManager.constants.genreHorror());
	}
	
	/**Mystery genre.*/
	public static final Genre mystery() {
		return new Genre(MovManager.constants.genreMystery());
	}
	
	/**Music genre.*/
	public static final Genre music() {
		return new Genre(MovManager.constants.genreMusic());
	}
	
	/**Musical genre.*/
	public static final Genre musical() {
		return new Genre(MovManager.constants.genreMusical());
	}
	
	/**Romance genre.*/
	public static final Genre romance() {
		return new Genre(MovManager.constants.genreRomance());
	}
	/**Science Fiction genre.*/
	public static final Genre sciencefiction() {
		return new Genre(MovManager.constants.genreScienceFiction());
	}
	
	/**Sport genre.*/
	public static final Genre sport() {
		return new Genre(MovManager.constants.genreSport());
	}
	
	/**Thriller genre.*/
	public static final Genre thriller() {
		return new Genre(MovManager.constants.genreThriller());
	}
	
	/**Western genre.*/
	public static final Genre western() {
		return new Genre(MovManager.constants.genreWestern());
	}
	
	/**
	 * Gets a genre by its string representation.
	 * 
	 * @param	name
	 * 			name of the genre
	 * @throws	NoSuchGenreException
	 * 			the genre does not exist
	 */
	public static final Genre getGenre(String name) throws NoSuchGenreException {
		for (Genre g: values())
			if (g.getName().equals(name))
				return g;
		throw new NoSuchGenreException("The genre " + name + " does not exist.");
	}
	
	/**
	 * Creates a list of genres by its string representations.
	 * 
	 * @param	genresString
	 * 			a list of genre strings
	 * @return	a list of genres
	 */
	public static final List<Genre> getGenres(List<String> genresString) {
		List<Genre> result = new ArrayList<Genre>();
		
		for (String s: genresString) {
			try {
				Genre g = getGenre(s);
				if (!result.contains(g))
					result.add(getGenre(s));
			} catch (NoSuchGenreException e) {
				// skip this genre string
			}
		}
		
		return result;
	}
	
	@Override
	public boolean equals(Object o) {
		if (!(o instanceof Genre))
			return false;
		
		Genre other = (Genre) o;
		return getName().equals(other.getName());
	}
}